﻿using System;
using System.Collections.Generic;
using Serilog;

// using net.vieapps.Components.WebSockets;
// using net.vieapps.Components.Utility;
// using net.vieapps.Components.WebSockets.Exceptions;
// using System.Net.WebSockets;

using System.Configuration;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

using Microsoft.EntityFrameworkCore;
using WebSocketSharp;
using WebSocketSharp.Net.WebSockets;
using WebSocketSharp.Server;

using Autofac;

namespace CoworkspaceAdmin.Server
{
    using CoworkspaceAdmin.Controller;

    public class Client2 {

        static string UnAuthedToken = "{\"msg_type\":\"unlogin\"}";
        public bool IsAuthed { get; set; }
        string userID;
        string password;
        WebSocket ws;

        public ProcessingMessageType nextMessageType {get; set;} = ProcessingMessageType.Text;



        public Client2(WebSocket s)
        {
            ws = s;
        }

        public void Reply(string msg)
        {
            if (ws is null) return;
            // ws.SendAsync(msg, true);
            ws.Send(msg);
        }

        public void ReplyUnAuthed()
        {
            Reply(UnAuthedToken);
        }


        public void Disconnect()
        {
            if (!(ws is null))
            {
                ws.CloseAsync(CloseStatusCode.Normal);
            }
        }
    }

    public class AdminBehavior : WebSocketBehavior {
        
        protected override void OnOpen() {
            Serilog.Log.Debug("connect open: {0}", Context.UserEndPoint.ToString());
        }

        protected override void OnClose(CloseEventArgs e) {
            Serilog.Log.Debug("close: {0}", e.Reason);
        }

        protected override void OnError(ErrorEventArgs e) {
            Serilog.Log.Error("error: {0}", e.Message);
        }

        protected override void OnMessage(MessageEventArgs e) {

            if(e.IsPing) {
                // Do something to notify that a ping has been received.
                Serilog.Log.Debug("recevi a ping");
                return;
            }

            if (e.IsText) {
                // Do something with e.Data.
                Serilog.Log.Debug("recv msg: {0}", e.Data);
                
            }

            if (e.IsBinary) {
                // Do something with e.RawData.
                Serilog.Log.Debug("recv msg: {0}", e.RawData);
                
            }
        }
    }

    public class Server2
    {
        Dictionary<Guid, Client> clients = new Dictionary<Guid, Client>();
        WebSocketServer wsSrv;

        public Server2()
        {
            Log.Information("Server create ...");
            
        }

        public void Start()
        {
            int port = Convert.ToInt32(ConfigurationManager.AppSettings.Get("ServerPort"));
            wsSrv = new WebSocketServer(port);
            wsSrv.Log.Level = LogLevel.Trace;
            
            // wsSrv.AddWebSocketService<AdminBehavior>("/");
            wsSrv.AddWebSocketService<AdminBehavior>(
                "/",
                (AdminBehavior ad) => {
                    ad.OriginValidator = val => {
                            Uri origin;
                            Uri.TryCreate (val, UriKind.Absolute, out origin);
                            Serilog.Log.Debug("origin raw: {0}", origin.OriginalString);
                            Serilog.Log.Debug("origin Query: {0}", origin.Query);
                            Serilog.Log.Debug("origin Segments: {0}", origin.Segments);
                            Serilog.Log.Debug("origin Scheme: {0}", origin.Scheme);
                            Serilog.Log.Debug("origin UserInfo: {0}", origin.UserInfo);
                            Serilog.Log.Debug("origin Fragment: {0}", origin.Fragment);
                            Serilog.Log.Debug("origin PathAndQuery: {0}", origin.PathAndQuery);
                            // return !val.IsNullOrEmpty ();
                            return true;
                        };
                    ad.CookiesValidator = (req, res) => {
                            // Check the cookies in 'req', and set the cookies to send to
                            // the client with 'res' if necessary.
                            foreach (WebSocketSharp.Net.Cookie cookie in req) {
                                cookie.Expired = true;
                                res.Add (cookie);
                            }

                            return true; // If valid.
                        };
                }
            );
            // wsSrv.Realm = "ygAdmin";

            // wsSrv.AuthenticationSchemes = WebSocketSharp.Net.AuthenticationSchemes.Basic;
            // wsSrv.UserCredentialsFinder = id => {
                
            //     /*  todo use id.Name to find the password. then return a new NetworkCredential (name, "password") 
            //         the name and password will be used in auth process.

            //         *** for client: ws.SetCredentials ("nobita", "password", preAuth);
            //         If preAuth is true, the client will send the credentials for the 
            //         Basic authentication in the first handshake request to the server.
            //         Otherwise, it will send the credentials for either the Basic or Digest 
            //         (determined by the unauthorized response to the first handshake request) 
            //         authentication in the second handshake request to the server.
            //     */
            //     Log.Debug("try user auth: {0}", id.Name);
            //     return new WebSocketSharp.Net.NetworkCredential(id.Name, "123456");

            //     // return null;
            // };

            wsSrv.Start();
            Serilog.Log.Debug("server start.");
        }

        public void Stop()
        {
            wsSrv.Stop();
        }

        private void MessageProcess(JObject jObject, ref Client ws)
        {
            
        }

        public void test()
        {
            // var manager = Program.GetSingletonService<ICompanyManager>();
            // manager.RemoveCompany("in service");
            // try{
            //     var e = JObject.Parse("{abc:der");
            // }catch{
            //     Log.Debug("UnParse message.");
            // }
            using (var scope = Program.Container.BeginLifetimeScope()){
            var ctx = scope.Resolve<Models.postgresContext>();
            Log.Debug("ctx 1: {0}", ctx);
            ctx.User.Remove(new Models.User(){
                Company = "成都三医智汇科技有限公司",
                Id = "123",
                Name = "like"
            });
            ctx.SaveChanges();
            }
        }
    }
}
